package com.lemon.cloud.generator.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.creator.druid.DruidConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lemon.cloud.comm.exception.BusinessException;
import com.lemon.cloud.core.utils.SpringContextHolder;
import com.lemon.cloud.generator.entity.GenDatasourceConf;
import com.lemon.cloud.generator.mapper.GenDatasourceConfMapper;
import com.lemon.cloud.generator.service.GenDatasourceConfService;
import com.lemon.cloud.mybatis.support.DataSourceConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
@RequiredArgsConstructor
public class GenDatasourceConfServiceImpl extends ServiceImpl<GenDatasourceConfMapper, GenDatasourceConf> implements GenDatasourceConfService {

    private final DefaultDataSourceCreator hikariDataSourceCreator;

    /**
     *
     * 列表
     * @param tableName 参数集
     * @param dsName 数据源编号
     * @return 数据库表
     * @return
     */
    @Override
    public IPage<List<Map<String, Object>>> getPage(Page<GenDatasourceConf> page, String tableName, String dsName) {
        page.setOptimizeCountSql(false);
        return baseMapper.queryList(page, tableName);
    }

    @Override
    public Boolean saveDsByEnc(GenDatasourceConf conf) {
        // 校验配置合法性
        if (!checkDataSource(conf)) {
            return Boolean.FALSE;
        }

        // 添加动态数据源
        addDynamicDataSource(conf);

        // 更新数据库配置
        AES aes = SecureUtil.aes(DataSourceConstants.AES_ENCRYPTOR_KEY.getBytes());
        conf.setPassword(aes.encryptHex(conf.getPassword()));
        this.baseMapper.insert(conf);
        return Boolean.TRUE;
    }


    /**
     * 更新数据源
     * @param conf 数据源信息
     * @return
     */
    @Override
    public Boolean updateDsByEnc(GenDatasourceConf conf) {
        if (!checkDataSource(conf)) {
            return Boolean.FALSE;
        }
        // 先移除
        DynamicRoutingDataSource dynamicRoutingDataSource = SpringContextHolder.getBean(DynamicRoutingDataSource.class);
        dynamicRoutingDataSource.removeDataSource(baseMapper.selectById(conf.getId()).getName());

        // 再添加
        addDynamicDataSource(conf);

        // 更新数据库配置
        if (StrUtil.isNotBlank(conf.getPassword())) {
            AES aes = SecureUtil.aes(DataSourceConstants.AES_ENCRYPTOR_KEY.getBytes());
            conf.setPassword(aes.encryptHex(conf.getPassword()));
        }
        this.baseMapper.updateById(conf);
        return Boolean.TRUE;
    }

    /**
     * 添加动态数据源
     * @param conf 数据源信息
     */
    @Override
    public void addDynamicDataSource(GenDatasourceConf conf) {
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        dataSourceProperty.setPoolName(conf.getName());
        dataSourceProperty.setUrl(conf.getUrl());
        dataSourceProperty.setUsername(conf.getUsername());
        dataSourceProperty.setPassword(conf.getPassword());

        // 增加 ValidationQuery 参数
        DruidConfig druidConfig = new DruidConfig();
        dataSourceProperty.setDruid(druidConfig);
        DataSource dataSource = hikariDataSourceCreator.createDataSource(dataSourceProperty);

        DynamicRoutingDataSource dynamicRoutingDataSource = SpringContextHolder.getBean(DynamicRoutingDataSource.class);
        dynamicRoutingDataSource.addDataSource(dataSourceProperty.getPoolName(), dataSource);
    }

    @Override
    public Boolean removeByDsId(Long id) {
        DynamicRoutingDataSource dynamicRoutingDataSource = SpringContextHolder.getBean(DynamicRoutingDataSource.class);
        GenDatasourceConf ds = this.baseMapper.selectById(id);
        if (ds!=null){
            dynamicRoutingDataSource.removeDataSource(ds.getName());
            this.baseMapper.deleteById(id);
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean checkDataSource(GenDatasourceConf conf) {
        //检测有没有重名的
        Long count = this.baseMapper.selectCount(new LambdaQueryWrapper<GenDatasourceConf>()
                .eq(GenDatasourceConf::getName, conf.getName())
                .ne(conf.getId() != null, GenDatasourceConf::getId, conf.getId()));
        if (count>0){
            throw new BusinessException("数据库配置错误，存在重复名称");
        }
        try (Connection ignored = DriverManager.getConnection(conf.getUrl(), conf.getUsername(), conf.getPassword())) {
        }
        catch (SQLException e) {
            log.error("数据源配置 {} , 获取链接失败", conf.getName(), e);
            throw new BusinessException("数据库配置错误，链接失败");
        }
        return Boolean.TRUE;
    }
}

